package modules.loader
{
	import modules.loader.IFactoryModule;
	import modules.loader.c_ModuleLoader;
	import sdk3.c_ARRAY;
	import sdk3.c_OBJECT;
	import sdk3.c_SORT;
	import sdk3.c_STRING;
	
	import sdk3.components.ResizableTitleWindow.ResizableTitleWindow;
	import sdk3.components.remoteService.readXMLconfig;
	
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.MouseEvent;
	
	import mx.containers.Box;
	import mx.containers.Canvas;
	import mx.containers.HBox;
	import mx.containers.TabNavigator;
	import mx.containers.VBox;
	import mx.containers.ViewStack;
	import mx.controls.Button;
	import mx.controls.Label;
	import mx.core.Container;
	import mx.core.IFlexDisplayObject;
	import mx.core.IFlexModule;
	import mx.events.FlexEvent;
	import mx.events.IndexChangedEvent;
	import mx.events.ModuleEvent;
	import mx.managers.IFocusManagerComponent;
	import mx.managers.IFocusManagerContainer;
	import mx.managers.PopUpManager;
	import mx.modules.IModuleInfo;
	import mx.modules.Module;
	import mx.modules.ModuleLoader;
	import mx.modules.ModuleManager;
	import mx.modules.ModuleManagerGlobals;
	import mx.rpc.events.ResultEvent;

	public class QueueModuleLoader
	{

		/*******************************************************************************
		 * Software: QueueModuleLoader.as		
		 * Version:  1.1
		 * based on Flex-SDK: 3.0   
		 * Date:     2010_05_08_TIME_21:12:32 - 2010_07_15_TIME_18:19:59
		 * Author:    
		 * 	  * LICENSE:  GNU General Public License (http://www.gnu.org/licenses/gpl.html) 	 *  	 * English: 		This program is free software; 		you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; 		either version 3 of the License, or (at your option) any later version.   		This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 		without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 		See the GNU General Public License for more details. 		You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.   		 * Excerpt English: 		 * Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), 		 * that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things   		Auf Deutsch: 		Dieses Programm ist freie Software. Sie können es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation veröffentlicht, 		weitergeben und/oder modifizieren, entweder gemäß Version 3 der Lizenz oder (nach Ihrer Option) jeder späteren Version. 		Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, daß es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, 		sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. 		Details finden Sie in der GNU General Public License. 		Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. 		Falls nicht, siehe <http://www.gnu.org/licenses/>.   		 * Auszug Deutsch: 		 * Wenn wir von freier Software sprechen, so beziehen wir uns auf Freiheit, nicht auf den Preis. 		 * Unsere Allgemeinen Öffentlichen Lizenzen sind darauf angelegt, sicherzustellen, daß Sie die Freiheit haben, 		 * Kopien freier Software zu verbreiten (und dafür etwas zu berechnen, wenn Sie möchten), die Möglichkeit, 		 * daß Sie die Software als Quelltext erhalten oder den Quelltext auf Wunsch bekommen, daß Sie die Software 		 * ändern oder Teile davon in neuen freien Programmen verwenden dürfen und daß Sie wissen, daß Sie dies alles tun dürfen.   GNU General Public License (http://www.gnu.org/licenses/gpl.html) 	 *  	 * English: 		This program is free software; 		you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; 		either version 3 of the License, or (at your option) any later version.   		This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 		without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 		See the GNU General Public License for more details. 		You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.   		 * Excerpt English: 		 * Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), 		 * that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things   		Auf Deutsch: 		Dieses Programm ist freie Software. Sie können es unter den Bedingungen der GNU General Public License, wie von der Free Software Foundation veröffentlicht, 		weitergeben und/oder modifizieren, entweder gemäß Version 3 der Lizenz oder (nach Ihrer Option) jeder späteren Version. 		Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, daß es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, 		sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. 		Details finden Sie in der GNU General Public License. 		Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem Programm erhalten haben. 		Falls nicht, siehe <http://www.gnu.org/licenses/>.   		 * Auszug Deutsch: 		 * Wenn wir von freier Software sprechen, so beziehen wir uns auf Freiheit, nicht auf den Preis. 		 * Unsere Allgemeinen Öffentlichen Lizenzen sind darauf angelegt, sicherzustellen, daß Sie die Freiheit haben, 		 * Kopien freier Software zu verbreiten (und dafür etwas zu berechnen, wenn Sie möchten), die Möglichkeit, 		 * daß Sie die Software als Quelltext erhalten oder den Quelltext auf Wunsch bekommen, daß Sie die Software 		 * ändern oder Teile davon in neuen freien Programmen verwenden dürfen und daß Sie wissen, daß Sie dies alles tun dürfen. 
		 * 
		 * Purpose:
		 * this class is about esatblishing an infrastructure to handel a queue that
		 * it was designed around the TabEditor as CONTAINER but other containers can be used as well.
		 * 
		 * i will try to load modules inside a resizable (titlewindow) popup.   
		 * 
		 * features:
		 * update the whole table, by just providing a SINGLE FLEX-ARRAY!
		 * 
		 * REQUIREMENTS WHAT ELSE IS NEEDED:
		 * currently only working with TabNavigator as CONTAINER
		 * 
		 * 1.) USAGE EXAMPLE:

			// makes it possible to load modules in groups
			public var LIST_OF_AVAILABLE_MODULES:Array =
			[
				{MODULEURL:"./modules/mxml/MODULE_module1.swf",GROUP:"Buchungserfassung",NAME:"Buchungserfassung"},
				{MODULEURL:"./modules/mxml/MODULE_OPsVerrechnen.swf",GROUP:"OP BEARBEITEN",NAME:"OPsVerrechnen"},
				{MODULEURL:"./modules/mxml/MODULE_Nachlassbuchung_extends_Buchungserfassung.swf",GROUP:"OP BEARBEITEN",NAME:"Nachlassbuchung"},
				{MODULEURL:"./modules/mxml/MODULE_OPBearbeiten.swf",GROUP:"OP BEARBEITEN",NAME:"OPBearbeiten"},
				{MODULEURL:"./modules/mxml/MODULE_OPsAnzeigen.swf" ,GROUP:"OP BEARBEITEN",NAME:"OPsAnezigen"},
				{MODULEURL:"./modules/mxml/MODULE_Nachlassbuchung.swf",GROUP:""}
			];

			import modules.loader.QueueModuleLoader;
			public var QueueModuleLoader_inst:QueueModuleLoader = new QueueModuleLoader(TAB_NAVIGATOR,LIST_OF_AVAILABLE_MODULES);


  		 	QueueModuleLoader_inst.LOAD_MODULE_GROUP("OP BEARBEITEN",LIST_OF_AVAILABLE_MODULES);
			// QUEUE_MODULE_FOR_LOADING("./modules/mxml/MODULE_OPBearbeiten.swf","OP BEARBEITEN");
			// QUEUE_MODULE_FOR_LOADING("./modules/mxml/MODULE_OPsAnzeigen.swf","OP BEARBEITEN");
		 * 
		 * 2.) USAGE EXAMPLE: MODE == "load modules as resizable popups,x=0,y=50,percentWidth=100%,percentHeight=100%,minimumY=50,maximumY=unlimited,minimumX=unlimited,maximumX=unlimited"
		 * in this case, popupManager is used which does not exist in "normal" containers
		 * 
			import modules.loader.QueueModuleLoader;
			public var QueueModuleLoader_inst:QueueModuleLoader = new QueueModuleLoader(this,LIST_OF_AVAILABLE_MODULES,"load modules as resizable popups,x=0,y=50,percentWidth=100%,percentHeight=100%,minimumY=50,maximumY=unlimited,minimumX=unlimited,maximumX=unlimited");

  		 	QueueModuleLoader_inst.LOAD_MODULE_GROUP("OP BEARBEITEN",LIST_OF_AVAILABLE_MODULES);
			// QUEUE_MODULE_FOR_LOADING("./modules/mxml/MODULE_OPBearbeiten.swf","OP BEARBEITEN");
			// QUEUE_MODULE_FOR_LOADING("./modules/mxml/MODULE_OPsAnzeigen.swf","OP BEARBEITEN");
		 * 
		 * CHANGELOG:
		 * 2010_08_08_TIME_18:01:54
		 * YEAHHHHH...... dynamic loading flash modules into application viewing in viewstack works..... changing views.....
			[08.08.10 17:59:16] (y) (dance)
			[08.08.10 17:59:35] die weltherrschaft steht unmittelbar bevor......
		 * **********************************************************/
		public var c_OBJECT_inst:c_OBJECT = new c_OBJECT();
		
		/** MODE passes additional values
		 * possible values: "load modules as resizable popups,x=0,y=50,percentWidth=100%,percentHeight=100%,minimumY=50,maximumY=unlimited,minimumX=unlimited,maximumX=unlimited" -> loads all modules inside a resizable popup container **/
		public var MODE:String = "";
		
		public function QueueModuleLoader(CONTAINER:* = null,LIST_OF_AVAILABLE_MODULES:Array = null,MODE:String = "")
		{
			this_inst = this;

			if(CONTAINER != null)
			{
				this._CONTAINER = CONTAINER;
			}

			if(LIST_OF_AVAILABLE_MODULES != null)
			{
				this.LIST_OF_AVAILABLE_MODULES = LIST_OF_AVAILABLE_MODULES;
			}
			
			if(c_OBJECT_inst.not_empty(MODE))
			{
				this.MODE = MODE;
			}
		}

		/** MODULE_OPsAnzeigen -> singleton implementation, um statt Application.application
		 * via MODULE_OPsAnzeigen.singleton() auf variablen und funktionen der MODULE_OPsAnzeigen zugreifen zu können. **/ 
		private static var this_inst:QueueModuleLoader = null;
		
		public static function singleton():QueueModuleLoader
		{
			return this_inst;
		}

		/** makes it possible to load modules in groups **/
		public var LIST_OF_AVAILABLE_MODULES:Array = null;
/*
			Example Values:
		 	[
				{MODULEURL:"./modules/mxml/MODULE_module1.swf"							,GROUP:"Buchungserfassung"		,NAME:"Buchungserfassung"},
				{MODULEURL:"./modules/mxml/MODULE_OPsVerrechnen.swf"								,GROUP:"OP BEARBEITEN"						,NAME:"OPsVerrechnen"},
				{MODULEURL:"./modules/mxml/MODULE_Nachlassbuchung_extends_Buchungserfassung.swf"	,GROUP:"OP BEARBEITEN"						,NAME:"Nachlassbuchung"},
				{MODULEURL:"./modules/mxml/MODULE_OPBearbeiten.swf"									,GROUP:"OP BEARBEITEN"						,NAME:"OPBearbeiten"},
				{MODULEURL:"./modules/mxml/MODULE_Calculator.swf"									,GROUP:""														,NAME:"Calculator"},
				{MODULEURL:"./modules/mxml/MODULE_OPErfassen.swf"						            ,GROUP:""														,NAME:"OPErfassen"},
				{MODULEURL:"./modules/mxml/MODULE_OPsAnzeigen.swf"									,GROUP:"OP BEARBEITEN"						,NAME:"OPsAnzeigen"}
			];
*/
		/** makes it possible to load modules in groups **/
		public function LOAD_MODULE_GROUP(GROUP:String,PARAMETER:* = null):void
		{
			for each(var OBJECT:Object in this.LIST_OF_AVAILABLE_MODULES)
			{
				if(OBJECT['GROUP'] == GROUP)
				{
					QUEUE_MODULE_FOR_LOADING(OBJECT['MODULEURL'],PARAMETER           ,GROUP           ,OBJECT['NAME']  ,OBJECT['STATUS']);
			     // QUEUE_MODULE_FOR_LOADING(MODULEURL:String   ,PARAMETER:* = null ,GROUP:String = '',NAME:String = '',STATUS:String = ''):void
				}
			}
		}

		/** load single module, identified by a NAME **/
		public function LOAD_MODULE(NAME:String,PARAMETER:* = null):void
		{
			for each(var OBJECT:Object in this.LIST_OF_AVAILABLE_MODULES)
			{
				if(OBJECT['NAME'] == NAME)
				{
					QUEUE_MODULE_FOR_LOADING(OBJECT['MODULEURL'],PARAMETER          ,OBJECT['GROUP']  ,NAME            ,OBJECT['STATUS']);
					// QUEUE_MODULE_FOR_LOADING(MODULEURL:String,PARAMETER:* = null ,GROUP:String = '',NAME:String = '',STATUS:String = ''):void

				}
			}
		}

		/** makes it possible to UN-load modules in groups **/
		public function UNLOAD_MODULE_GROUP(GROUP:String):void
		{
			// collect indices
			var TO_UNLOAD:Array = new Array();
			for each(var OBJECT:Object in LIST_OF_AVAILABLE_MODULES)
			{
				if(OBJECT['GROUP'] == GROUP)
				{
					TO_UNLOAD.push(MODULE_LOADER.UNLOAD_MODULE(OBJECT['MODULEURL']));
				}
			}
			
			// sort
			TO_UNLOAD = c_SORT.singleton().SORT(TO_UNLOAD,'INDEX','DSC');
			
			// remove
			for each(var OBJECT:Object in TO_UNLOAD)
			{
				removeTab(OBJECT['INDEX']);
			}
		}
		
		/** makes it possible to UN-load a given module
		 * URL_OR_NAME
		 * -> "ALL" -> all loaded modules will be unloaded.
		 * **/
		public function UNLOAD_MODULE(URL_OR_NAME:String):void
		{
			// collect indices
			var TO_UNLOAD:Array = new Array();
			var MODULEURL:String = NAME_TO_URL(URL_OR_NAME);

			if(URL_OR_NAME == "ALL")
			{
				// unload all loaded modules
				for(var MODULEURL:String in MODULE_LOADER.MODULE_INTERFACES)
				{
					if(IS_LOADED(MODULEURL))
					{
						MODULE_LOADER.UNLOAD_MODULE(MODULEURL);
					}
				}
				// remove children from container
				_CONTAINER.removeAllChildren();
				numChild = 0;
			}
			else
			{
				for each(var OBJECT:Object in LIST_OF_AVAILABLE_MODULES)
				{
					if(OBJECT['MODULEURL'] == MODULEURL)
					{
						if(IS_LOADED(MODULEURL))
						{
							try
							{
								if(MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['CONTAINER'] is ResizableTitleWindow)
								{
									removeResizableTitleWindow(MODULEURL);
									break;
								}
								else
								{
									removeTab(MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INDEX']);
									break;
								}
							}
							catch(e:Error)
							{ }

							TO_UNLOAD.push(MODULE_LOADER.UNLOAD_MODULE(MODULEURL));
						}
					}
				}
			}

/*			// sort
			TO_UNLOAD = c_SORT.singleton().SORT(TO_UNLOAD,'INDEX','DSC');

			// remove
			for each(var OBJECT:Object in TO_UNLOAD)
			{
				try
				{
					removeTab(OBJECT['INDEX']);
				}
				catch(e:Error)
				{
					trace("QueueModuleLoader.as: "+e);
				}
			}
*/		}
		
		/** 
		 * changes the tabs on command.
		 * INPUT:
		 * MODULEURL_OR_NAME
		 * NAME:
		 * -> if a name property was given to the module: LIST_OF_AVAILABLE_MODULES, will first evaluate this... than the url.
		 * URL:
		 * -> relative url pointing to the MODULE_Name.swf starting from mainapp.mxml.
		 * -> example: "./modules/mxml/MODULE_OPBearbeiten.swf"
		 * MODE
		 * -> 'switch view only' -> will only switch to the tabIndex of the given moduleurl, but not pass any parameter or call initApp()
		 * **/
		public var SWITCH_TO_THIS_MODULE_RIGHT_AFTER_LOADING:String = '';
		public function changeView(MODULEURL_OR_NAME:String,PARAMETER:* = null):void
		{
			var MODULEURL:String = FIND_MODULE_GET_PROPERTY(MODULEURL_OR_NAME,'MODULEURL');

			if((MODULEURL == 'property of module not found') || (MODULEURL == 'module not found'))
			{
				trace("QueueModuleLoader: "+MODULEURL);
			}
			else
			{
				var loaded:Boolean = true;
				if(MODULE_LOADER.MODULE_INTERFACES[MODULEURL] == null)
				{
					loaded = false;
				}
				else if(MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INSTANCE'] == null)
				{
					loaded = false;
				}
				
				if(loaded == false)
				{
					// load module and then switch to this navtab
					SWITCH_TO_THIS_MODULE_RIGHT_AFTER_LOADING = MODULEURL;
					QUEUE_MODULE_FOR_LOADING(MODULEURL,PARAMETER,FIND_MODULE_GET_PROPERTY(MODULEURL_OR_NAME,'GROUP'),FIND_MODULE_GET_PROPERTY(MODULEURL_OR_NAME,'NAME'),FIND_MODULE_GET_PROPERTY(MODULEURL_OR_NAME,'STATUS'));
				}
				else
				{
					if(PARAMETER != null)
					{
						// module is loaded & instanciated, pass parameter & switch to it's view
						MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INSTANCE'].INIT_PARAM = PARAMETER;
						MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INSTANCE'].initApp();
					}

					if(_CONTAINER is TabNavigator)
					{
						if(MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['STATUS'] != 'ADDED TO DISPLAY')
						{
							addTab(MODULEURL);
						}
						else
						{
							_CONTAINER['selectedIndex'] = MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INDEX'];
						}
					}
					if(_CONTAINER is ViewStack)
					{
						if(MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['STATUS'] != 'ADDED TO DISPLAY')
						{
							addTab(MODULEURL);
						}
						else
						{
							_CONTAINER
							_CONTAINER['selectedIndex'] = MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INDEX'];
						}
					}
				}
			}
		}

		/** checks if a module identified by given URL_OR_NAME was loaded & instanciated **/
		public function IS_LOADED(URL_OR_NAME:String):Boolean
		{
			var MODULE_LOADED:Boolean = false;
			URL_OR_NAME = NAME_TO_URL(URL_OR_NAME);
			if(MODULE_LOADER.MODULE_INTERFACES[URL_OR_NAME] == null)
			{
				MODULE_LOADED = false;
			}
			else
			{
				if(MODULE_LOADER.MODULE_INTERFACES[URL_OR_NAME]['INSTANCE'] != null)
				{
					MODULE_LOADED = true;
				}
			}
			return MODULE_LOADED;
		}

		/** checks if a module identified by given URL_OR_NAME was loaded & is an existing DisplayObject inside the CONTAINER (probably TabNavigator) **/
		public function IS_DISPLAYED_INSIDE_CONTAINER(URL_OR_NAME:String):Boolean
		{
			var MODULE_DISPLAYED:Boolean = false;
			URL_OR_NAME = NAME_TO_URL(URL_OR_NAME);
			MODULE_DISPLAYED = _CONTAINER.contains(MODULE_LOADER.MODULE_INTERFACES[URL_OR_NAME]['INSTANCE']);
			return MODULE_DISPLAYED;
		}

		/** module2module, or module2parent communication:
		 * example function how to pass data to a (allready loaded) module **/
		/**
		 // read from variable
		 var SomeVar:String = c_BINGO_FIBU.singleton().MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INSTANCE'].SomeVariable;
		 // write to variable
		 c_BINGO_FIBU.singleton().MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INSTANCE'].SomeVariable = 'some value';
		 // call function and pass variabl
		 c_BINGO_FIBU.singleton().MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INSTANCE'].FunctionOfModule(SomeVariable);
		 // view module
		 c_BINGO_FIBU.singleton().CONTAINER.selectedIndex = c_BINGO_FIBU.singleton().MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INDEX'];
		 **/
		
		/** keeps a list of modules that need to be loaded, one after another
		 * MODULEURL -> relative url from the position of the parten.swf -> ./path/modul.swf
		 * PARAMETER -> if a modul should be passed data, pass a parameter.
		 * GROUP -> if a modul belongs to a group, pass a group-name as a string. 
		 * **/
		public var MODULE_LOADING_QUEUE:Array = new Array();
		public function QUEUE_MODULE_FOR_LOADING(MODULEURL:String,PARAMETER:* = null,GROUP:String = '',NAME:String = '',STATUS:String = ''):void
		{
			MODULE_LOADING_QUEUE.push({MODULEURL:MODULEURL,PARAMETER:PARAMETER,STATUS:'queued',GROUP:GROUP,NAME:NAME});
			START_TIMER_MODULE_LOADING();
		}
		
		import flash.events.TimerEvent;
		import flash.utils.Timer;
		
		/** a timer that executes every 100 milliseconds to process the MODULE_LOADING_QUEUE queue **/
		var MODULE_QUEUE_TIMER:Timer = new Timer(100, Infinity);
		public function START_TIMER_MODULE_LOADING():void
		{
			if(MODULE_QUEUE_TIMER.running == false)
			{
				if(MODULE_QUEUE_TIMER.hasEventListener(TimerEvent.TIMER) == false)
				{
					MODULE_QUEUE_TIMER.addEventListener(TimerEvent.TIMER, PROCESS_MODULE_LOADING_QUEUE);
				}
				MODULE_QUEUE_TIMER.start();
			}
		}
		
		public var MODULE_LOADER:c_ModuleLoader = new c_ModuleLoader();
		public function PROCESS_MODULE_LOADING_QUEUE(event:Event = null):void
		{
			if(event is TimerEvent)
			{
				if(MODULE_LOADER.hasEventListener("ready") == false)
				{
					MODULE_LOADER.addEventListener("ready", PROCESS_MODULE_LOADING_QUEUE);
				}
				// keep processing the queue
				if(MODULE_LOADING_QUEUE.length > 0)
				{
					if(MODULE_LOADING_QUEUE[0]['STATUS'] == 'queued')
					{
						MODULE_LOADING_QUEUE[0]['STATUS'] = 'loading';
						MODULE_LOADER.LOAD_MODULE(MODULE_LOADING_QUEUE[0]['MODULEURL'],MODULE_LOADING_QUEUE[0]['PARAMETER'],MODULE_LOADING_QUEUE[0]['GROUP'],MODULE_LOADING_QUEUE[0]['NAME'],MODULE_LOADING_QUEUE[0]['STATUS']);
					}
					/* 						if(MODULE_LOADING_QUEUE[0]['STATUS'] == 'unload')
					{
					MODULE_LOADING_QUEUE[0]['STATUS'] = 'unloading';
					var RESULT:Object = MODULE_LOADER.UNLOAD_MODULE(MODULE_LOADING_QUEUE[0]['MODULEURL']);
					}
				*/					}
			}
			else
			{
				// probably "ready" event, finished loading the module on top of the queue
				MODULE_LOADING_QUEUE[0]['STATUS'] = 'ready';

				if(MODULE_LOADING_QUEUE[0]['PARAMETER'] != null)
				{
					// module is loaded & instanciated, pass parameter & switch to it's view
					MODULE_LOADER.MODULE_INTERFACES[MODULE_LOADING_QUEUE[0]['MODULEURL']]['INSTANCE'].INIT_PARAM = MODULE_LOADING_QUEUE[0]['PARAMETER'];
				}

				// add module to screen, in this case, inside a TabNavigator
				addTab(MODULE_LOADING_QUEUE[0]['MODULEURL']);
				MODULE_LOADING_QUEUE = c_ARRAY.singleton().pop_first(MODULE_LOADING_QUEUE);
			}
		}
		
		public function UNLOAD_ALL_MODULES():void
		{
			for(var KEY:String in MODULE_LOADER.MODULE_INTERFACES)
			{
				try
				{
					UNLOAD_MODULE(KEY);
				}
				catch(e:Error)
				{
					trace(e);
				}
			}
		}
		
		public var numChild:Number = 0;

		/** CONTAINER to which the Module will be added after loading **/
		private var _CONTAINER:Container = null;

		public function set CONTAINER(CONTAINER_var:Container):void
		{
			this._CONTAINER = CONTAINER_var;
		}
		public function get CONTAINER():Container
		{
			return this._CONTAINER;
		}

		/** converts a string like
		"load modules as resizable popups,x=0,y=50,percentWidth=100%,percentHeight=100%"
		 * 	loading_bar.percentHeight
			loading_bar.percentWidth

		 * into a object like
		 * **/				
		public function MODE2OBJECT(MODE:String):Object
		{
			if(c_OBJECT_inst.not_empty(MODE))
			{
				var MODE_OBJECT:Object = {x:0,y:0,width:100};
				var ELEMENTS:Array = this.MODE.split(",");
				var ELEMENT_ARRAY:Array = new Array();
				for each(var ELEMENT:String in ELEMENTS)
				{
					ELEMENT_ARRAY = ELEMENT.split("=");
					var STRING:String = ELEMENT_ARRAY[1];
					
					if(ELEMENT_ARRAY[0] == "percentWidth")
					{
						ELEMENT_ARRAY[1] = STRING.substring(0,STRING.length-1); // remove trailing % 
					}
					else if(ELEMENT_ARRAY[0] == "percentHeight")
					{
						ELEMENT_ARRAY[1] = STRING.substring(0,STRING.length-1); // remove trailing %
					}

					if(STRING == "unlimited")
					{
						MODE_OBJECT[ELEMENT_ARRAY[0]] = ELEMENT_ARRAY[1];
					}
					else
					{
						MODE_OBJECT[ELEMENT_ARRAY[0]] = parseFloat(ELEMENT_ARRAY[1]);
					}
				}
			}
			return MODE_OBJECT;
		}
		
		/** saves the X position of the last added popup **/
		public var lastWindowX:Number = 0;
		/** saves the Y position of the last added popup **/
		public var lastWindowY:Number = 0;
		
		/** adds the module to the CONTAINER
		 * OBJECT
		 * **/
		public function addTab(MODULEURL:String = ''):void
		{
			var MODE_OBJECT:Object = MODE2OBJECT(this.MODE);
				
			var DISPLAYOBJECT:DisplayObject = MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INSTANCE'] as DisplayObject;
			
			if(_CONTAINER is Container)
			{
				if(_CONTAINER is ViewStack)
				{
					var VIEWSTACK_CONTAINER:ViewStack = _CONTAINER as ViewStack;
					MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['CONTAINER'] = VIEWSTACK_CONTAINER;
					MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['STATUS'] = 'ADDED TO DISPLAY';
					VIEWSTACK_CONTAINER.removeAllChildren();
					VIEWSTACK_CONTAINER.addChild(DISPLAYOBJECT);
				}
				if(_CONTAINER is TabNavigator)
				{
					var TAB_CONTAINER:TabNavigator = _CONTAINER as TabNavigator;
					MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['CONTAINER'] = TAB_CONTAINER;

					var newVBox:VBox = new VBox();
	
					MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INDEX'] = numChild;
					numChild = TAB_CONTAINER.numChildren + 1;
	
					newVBox.addChild(DISPLAYOBJECT);
					newVBox.label = MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['NAME'];
	
					MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['STATUS'] = 'ADDED TO DISPLAY';
	
					TAB_CONTAINER.addChild(newVBox);
	
					if(c_OBJECT_inst.not_empty(SWITCH_TO_THIS_MODULE_RIGHT_AFTER_LOADING))
					{
						var DISPATCHER:EventDispatcher = MODULE_LOADER.MODULE_INTERFACES[SWITCH_TO_THIS_MODULE_RIGHT_AFTER_LOADING]['INSTANCE'] as EventDispatcher;
						
						SWITH_TO_TABINDEX = MODULE_LOADER.MODULE_INTERFACES[SWITCH_TO_THIS_MODULE_RIGHT_AFTER_LOADING]['INDEX'];
	
						// DISPATCHER.addEventListener(FlexEvent.CREATION_COMPLETE, NEXT_TAB); // did not work so well.
						// TAB_CONTAINER.addEventListener(FlexEvent.VALUE_COMMIT, NEXT_TAB);
						
						SWITCH_TO_THIS_MODULE_RIGHT_AFTER_LOADING = '';
						
						NEXT_TAB();
					}
				}
				else
				{
					if(MODE.substr(0,32) == "load modules as resizable popups")
					{
						/** add module as resizable popup to displaylist **/
						var RESIZABLE_POPUP:ResizableTitleWindow = new ResizableTitleWindow();
						MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['CONTAINER'] = RESIZABLE_POPUP;
						MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INDEX'] = numChild;
						numChild = _CONTAINER.numChildren + 1;
		
						// load modules as resizable popups,x=0,y=50,percentWidth=100%,percentHeight=100%,minimumY=50,maximumY=unlimited,minimumX=unlimited,maximumX=unlimited
						if(c_OBJECT_inst.not_empty(MODE_OBJECT["maximumX"]))
						{
							RESIZABLE_POPUP.maximumX = MODE_OBJECT["maximumX"];
						}
						if(c_OBJECT_inst.not_empty(MODE_OBJECT["minimumX"]))
						{
							RESIZABLE_POPUP.minimumX = MODE_OBJECT["minimumX"];
						}
						if(c_OBJECT_inst.not_empty(MODE_OBJECT["maximumY"]))
						{
							RESIZABLE_POPUP.maximumY = MODE_OBJECT["maximumY"];
						}
						if(c_OBJECT_inst.not_empty(MODE_OBJECT["minimumY"]))
						{
							RESIZABLE_POPUP.minimumY = MODE_OBJECT["minimumY"];
						}
						if(c_OBJECT_inst.not_empty(MODE_OBJECT["percentHeight"]))
						{
							RESIZABLE_POPUP.percentHeight = MODE_OBJECT["percentHeight"];
						}
						if(c_OBJECT_inst.not_empty(MODE_OBJECT["percentWidth"]))
						{
							RESIZABLE_POPUP.percentWidth = MODE_OBJECT["percentWidth"];
						}

						if(c_OBJECT_inst.not_empty(MODE_OBJECT["nextWindowX"]))
						{
							RESIZABLE_POPUP.nextWindowX = MODE_OBJECT["nextWindowX"];
						}
						if(c_OBJECT_inst.not_empty(MODE_OBJECT["nextWindowY"]))
						{
							RESIZABLE_POPUP.nextWindowY = MODE_OBJECT["nextWindowY"];
						}

						if(c_OBJECT_inst.not_empty(MODE_OBJECT["x"]))
						{
							if(isNaN(RESIZABLE_POPUP.nextWindowX))
							{
								RESIZABLE_POPUP.x = MODE_OBJECT["x"]+RESIZABLE_POPUP.nextWindowX+lastWindowX;
							}
							else
							{
								// save position of last popup window
								lastWindowX = RESIZABLE_POPUP.x = MODE_OBJECT["x"]+RESIZABLE_POPUP.nextWindowX+lastWindowX;
							}
						}
						if(c_OBJECT_inst.not_empty(MODE_OBJECT["y"]))
						{
							if(isNaN(RESIZABLE_POPUP.nextWindowY))
							{
								RESIZABLE_POPUP.y = MODE_OBJECT["y"]+RESIZABLE_POPUP.nextWindowY+lastWindowY;
							}
							else
							{
								// save position of last popup window
								lastWindowY = RESIZABLE_POPUP.y = MODE_OBJECT["y"]+RESIZABLE_POPUP.nextWindowY+lastWindowY;
							}
						}

						RESIZABLE_POPUP.addChild(DISPLAYOBJECT);
						// RESIZABLE_POPUP.id = MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['NAME'];
						// RESIZABLE_POPUP.name = MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['NAME'];
		
						MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['STATUS'] = 'ADDED TO DISPLAY';
		
						_CONTAINER.addChild(RESIZABLE_POPUP);
					}
					else
					{
						/** unspecified container, just add the module to it **/
						MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['INDEX'] = numChild;
						MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['CONTAINER'] = _CONTAINER;
						numChild = _CONTAINER.numChildren + 1;
		
						MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['STATUS'] = 'ADDED TO DISPLAY';
		
						_CONTAINER.addChild(DISPLAYOBJECT);
					}
				}
			}
		}

		/** event result handler, switch tabNavigation to not yet rendered modules, if not done on creationComplete tab will switch back to last tab. (fast switch forth & back)
		 * problem is that it still switched back & forth every once and a while... !?
		 * so i try inserting a little 0.1 delay 
		 * **/
		public var SWITH_TO_TABINDEX:int = 0;
		private var firstValueCommit:Boolean = true; //BUG 1234: argh........ because tabnav + modules are missbehaving... working around "back-and-forth-on-first-module-tab" error/bug
		public function NEXT_TAB(event:Event = null):void
		{
			if(_CONTAINER is TabNavigator)
			{
				var TAB_CONTAINER:TabNavigator = _CONTAINER as TabNavigator;
				TAB_CONTAINER.selectedIndex = SWITH_TO_TABINDEX;
				TAB_CONTAINER.dispatchEvent(new IndexChangedEvent(IndexChangedEvent.CHANGE,true,false));
			}
		}

		public function removeTab(INDEX:int):void
		{
			_CONTAINER.removeChildAt(INDEX);
			numChild = numChild - 1;
		}
		
		public function removeResizableTitleWindow(MODULEURL:String):void
		{
			var RTW:ResizableTitleWindow = MODULE_LOADER.MODULE_INTERFACES[MODULEURL]['CONTAINER'];
			RTW.closeHandler();
		}

		/** iterates through LIST_OF_AVAILABLE_MODULES and tries to find the appropriate url of the module **/ 
		public function NAME_TO_URL(NAME_OR_URL:String):String
		{
			var RESULT:String = 'url not found';
			for each(var MODULE:Object in LIST_OF_AVAILABLE_MODULES)
			{
				if((MODULE['MODULEURL'] == NAME_OR_URL) || (MODULE['NAME'] == NAME_OR_URL))
				{
					RESULT = MODULE['MODULEURL']
					break;
				}
			}
			
			return RESULT;
		}
		
		/** iterates through LIST_OF_AVAILABLE_MODULES and tries to find the appropriate url of the module **/ 
		public function URL_TO_NAME(NAME_OR_URL:String):String
		{
			var RESULT:String = 'name not found';
			for each(var MODULE:Object in LIST_OF_AVAILABLE_MODULES)
			{
				if((MODULE['MODULEURL'] == NAME_OR_URL) || (MODULE['NAME'] == NAME_OR_URL))
				{
					RESULT = MODULE['NAME']
					break;
				}
			}
			
			return RESULT;
		}

		/** iterates through LIST_OF_AVAILABLE_MODULES and tries to find the module identified by URL_OR_NAME and returns the given property **/ 
		public function FIND_MODULE_GET_PROPERTY(URL_OR_NAME:String,PROPERTY:String):String
		{
			var RESULT:String = 'module not found';
			for each(var MODULE:Object in LIST_OF_AVAILABLE_MODULES)
			{
				RESULT = 'property of module not found';
				if((MODULE['MODULEURL'] == URL_OR_NAME) || (MODULE['NAME'] == URL_OR_NAME))
				{
					RESULT = MODULE[PROPERTY]
					break;
				}
			}
			
			return RESULT;
		}
		
	}
}